using UnityEngine;

/// <summary>
/// ���ܷ�Χָʾ���ܿ�
/// </summary>
public class SkillAttackIndicators : MonoBehaviour
{
    [Header("ͨ��")]
    public IndicatorType IndicatorType;
    public Material IndicatorMaterial;

    [Header("���β���")]
    [Range(1f, 360f)] public float SectorAngle = 90f;
    [Range(0.1f, 20f)] public float SectorRadius = 5f;
    [Range(1, 60)] public int SectorQuality = 20;

    [Header("OBB ����")]
    public Vector3 ObbHalfExtents = Vector3.one;
    public Vector3 ObbRotationEuler = Vector3.zero;
    public Vector3 ObbFillDirection = Vector3.forward;

    [Header("Բ�β���")]
    [Range(0.001f, 20f)] public float CircleRadius = 3f;
    [Range(3, 60)] public int CircleQuality = 20;

    [Header("���β���")]
    [Range(0.1f, 20f)] public float RectangleWidth = 3f;
    [Range(0.1f, 20f)] public float RectangleLength = 6f;

    [Header("���������")]
    [Range(0.1f, 10f)] public float CapsuleRadius = 1f;
    [Range(0.1f, 20f)] public float CapsuleHeight = 3f;

    [Header("������Ͷ�����")]
    [Range(0.1f, 5f)] public float CapsuleCastRadius = 0.5f;
    [Range(0.1f, 10f)] public float CapsuleCastHeight = 2f;
    [Range(0.1f, 100f)] public float CapsuleCastRange = 10f;

    [Header("Բ׶����")]
    [Range(1f, 179f)] public float ConeAngle = 45f;
    [Range(0.1f, 20f)] public float ConeHeight = 5f;
    [Range(3, 60)] public int ConeQuality = 24;

    [Header("����Ȧ����")]
    [Range(0.1f, 20f)] public float DonutInnerRadius = 2f;
    [Range(0.1f, 20f)] public float DonutOuterRadius = 5f;
    [Range(3, 60)] public int DonutQuality = 36;

    [Header("ʮ���β���")]
    [Range(0.1f, 10f)] public float CrossHalfWidth = 1f;
    [Range(0.1f, 20f)] public float CrossMaxLength = 3f;

    [Header("����Ͷ�����")]
    [Range(0.1f, 5f)] public float SphereCastRadius = 0.5f;
    [Range(0.1f, 100f)] public float SphereCastRange = 10f;

    [Header("�����߲���")]
    [Range(1f, 100f)] public float ParabolaProjectileSpeed = 10f;
    [Range(0.1f, 20f)] public float ParabolaImpactRadius = 3f;
    [Range(0.1f, 20f)] public float ParabolaGravity = 9.8f;

    [Header("����")]
    public bool EnableCharging = false;
    [Range(0.1f, 10f)] public float MinChargeTime = 0.2f;
    [Range(0.1f, 10f)] public float MaxChargeTime = 2f;
    [Range(0f, 1f)] public float MinRangeScale = 0.5f;
    [Range(0f, 1f)] public float MaxRangeScale = 1f;
    [Range(0f, 1f)] public float MinAngleScale = 0.5f;
    [Range(0f, 1f)] public float MaxAngleScale = 1f;
    public Color ChargeFillColor = new Color(0, 1, 0, 0.5f);
    public Color ChargeCompleteColor = new Color(1, 0, 0, 0.5f);
    [Range(0.01f, 1f)] public float FillSmoothness = 0.1f;

    private IAttackIndicator m_BaseIndicator;      // ��פ��ʾ�Ļ���ָʾ��
    private IAttackIndicator m_ChargingIndicator;  // ����ʱ��ʾ��ָʾ��
    private GameObject m_IndicatorRoot;            // ָʾ�����ڵ�

    private GameObject m_BaseIndicatorObj;         // ����ָʾ���ڵ�
    private GameObject m_ChargingIndicatorObj;     // ����ָʾ���ڵ�

    private IndicatorType m_LastIndicatorType;
    private IndicatorData m_IndicatorData;           // 从 EntityData 读取的指示器数据     // ��¼�ϴε�ָʾ������

    /* ---------- �������� ---------- */

    /// <summary>
    /// 初始化指示器，从 EntityData 读取 IndicatorData
    /// </summary>
    /// <param name="indicatorData">指示器数据</param>
    public void Initialize(IndicatorData indicatorData = null)
    {
        IndicatorMaterial = Resources.Load<Material>("Material/Indicator_Material");
        
        // 如果提供了 IndicatorData，则使用它来初始化参数
        if (indicatorData != null)
        {
            m_IndicatorData = indicatorData;
            LoadParamsFromIndicatorData();
        }
    }

    /// <summary>
    /// 从 IndicatorData 读取参数并应用到字段
    /// </summary>
    private void LoadParamsFromIndicatorData()
    {
        if (m_IndicatorData == null) return;

        // 设置指示器类型
        IndicatorType = m_IndicatorData.IndicatorType;

        // 根据不同的 IndicatorData 子类类型读取参数
        switch (m_IndicatorData)
        {
            case SectorIndicatorData sectorData:
                SectorAngle = sectorData.Angle;
                SectorRadius = sectorData.Radius;
                SectorQuality = sectorData.Quality;
                break;

            case CirlcleIndicatorData circleData:
                CircleRadius = circleData.CircleRadius;
                CircleQuality = circleData.CircleQuality;
                break;

            case RectangleIndicatorData rectData:
                RectangleWidth = rectData.RectangleWidth;
                RectangleLength = rectData.RectangleLength;
                break;

            case CapsuleIndicatorData capsuleData:
                CapsuleRadius = capsuleData.CapsuleRadius;
                CapsuleHeight = capsuleData.CapsuleHeight;
                break;

            case ConeIndicatorData coneData:
                ConeAngle = coneData.ConeAngle;
                ConeHeight = coneData.ConeHeight;
                ConeQuality = coneData.ConeQuality;
                break;

            case DonutIndicatorData donutData:
                DonutInnerRadius = donutData.DonutInnerRadius;
                DonutOuterRadius = donutData.DonutOuterRadius;
                DonutQuality = donutData.DonutQuality;
                break;

            case CrossIndicatorData crossData:
                CrossHalfWidth = crossData.CrossHalfWidth;
                CrossMaxLength = crossData.CrossMaxLength;
                break;

            case ParabolaIndicatorData parabolaData:
                ParabolaProjectileSpeed = parabolaData.ParabolaProjectileSpeed;
                ParabolaImpactRadius = parabolaData.ParabolaImpactRadius;
                ParabolaGravity = parabolaData.ParabolaGravity;
                break;

            case SphereCastIndicatorData sphereCastData:
                SphereCastRadius = sphereCastData.SphereCastRadius;
                SphereCastRange = sphereCastData.SphereCastRange;
                break;

            case OBBIndicatorData obbData:
                ObbHalfExtents = obbData.ObbHalfExtents;
                ObbRotationEuler = obbData.ObbRotationEuler;
                ObbFillDirection = obbData.ObbFillDirection;
                break;

            case RingIndicatorData ringData:
                // Ring 和 Donut 使用相同的参数
                DonutInnerRadius = ringData.InnerRadius;
                DonutOuterRadius = ringData.OuterRadius;
                DonutQuality = ringData.Quality;
                break;

            case PieIndicatorData pieData:
                // Pie 使用 Sector 的参数
                SectorAngle = pieData.Angle;
                SectorRadius = pieData.Radius;
                SectorQuality = pieData.Quality;
                break;

            default:
                // 对于未知类型或基础 IndicatorData，只设置类型
                break;
        }
    }

    private void OnEnable()
    {
        CreateOrUpdateIndicators();
    }

    private void OnDisable()
    {
        CleanUpIndicators();
    }

#if UNITY_EDITOR
    private void OnValidate()
    {
        if (!UnityEditor.EditorApplication.isUpdating)
            UnityEditor.EditorApplication.delayCall += CreateOrUpdateIndicators;
    }
#endif

    /// <summary>
    /// ���������ָʾ��
    /// </summary>
    public void CreateOrUpdateIndicators()
    {
        if (this == null || transform == null) return;


#if UNITY_EDITOR
        if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this))
        {
            return;
        }
#endif

        // 1. ���ָʾ�������Ƿ�仯
        bool typeChanged = IndicatorType != m_LastIndicatorType;
        m_LastIndicatorType = IndicatorType;

        // 2. ����/���Ҹ��ڵ�
        CreateIndicatorRoot();

        // 3. ����/���»���ָʾ��
        CreateOrUpdateIndicator(
            ref m_BaseIndicator,
            ref m_BaseIndicatorObj,
            "BaseIndicator",
            false,
            typeChanged);

        // 4. ����/��������ָʾ��
        CreateOrUpdateIndicator(
            ref m_ChargingIndicator,
            ref m_ChargingIndicatorObj,
            "ChargingIndicator",
            true,
            typeChanged);
    }

    /// <summary>
    /// ����ָʾ�����ڵ�
    /// </summary>
    private void CreateIndicatorRoot()
    {
        Transform root = transform.Find("IndicatorRoot");
        if (root != null)
        {
            m_IndicatorRoot = root.gameObject;
            UpdateRootAngles();
            return;
        }

        m_IndicatorRoot = new GameObject("IndicatorRoot");
        m_IndicatorRoot.AddComponent<RectTransform>();
        m_IndicatorRoot.transform.SetParent(transform, false);
        m_IndicatorRoot.transform.localPosition = Vector3.zero;
        m_IndicatorRoot.transform.localRotation = Quaternion.identity;

        UpdateRootAngles();
    }

    private void UpdateRootAngles()
    {
        Vector3 angle = Vector3.zero;
        Vector3 pos = Vector3.zero;
        switch (IndicatorType)
        {
            case IndicatorType.Sector:
                angle = new Vector3(80, 0, 90);
                break;
            case IndicatorType.OBB:
                angle = new Vector3(80, 0, 90);
                break;
            case IndicatorType.Circle:
                angle = new Vector3(-80, 180, 180);
                break;
            case IndicatorType.Rectangle:
                angle = new Vector3(-15, 0, 0);
                break;
            case IndicatorType.Capsule:
                angle = new Vector3(80, 0, 90);
                break;
            case IndicatorType.Cross:
                angle = new Vector3(-15, 0, 0);
                break;
            case IndicatorType.Pie:
                angle = new Vector3(180, 90, 6);
                break;
            case IndicatorType.Ring:
                angle = new Vector3(-10, 0, 0);
                break;
            case IndicatorType.CapsuleCast:
                angle = new Vector3(0, 0, 0);
                break;
            case IndicatorType.Cone:
                angle = new Vector3(80, 0, 90);
                break;
            case IndicatorType.Donut:
                angle = new Vector3(80, 0, 90);
                break;
            case IndicatorType.Parabola:
                angle = new Vector3(85, 0, 90);
                pos = new Vector3(-4.6f, 4.6f, 0);
                break;
            case IndicatorType.SphereCast:
                angle = Vector3.zero;
                pos = new Vector3(0, 5f, 0);
                break;
            default:
                break;
        }

        m_IndicatorRoot.transform.localEulerAngles = angle;
        m_IndicatorRoot.transform.localPosition = pos;
    }

    /// <summary>
    /// ��������µ���ָʾ��
    /// </summary>
    private void CreateOrUpdateIndicator(
        ref IAttackIndicator indicator,
        ref GameObject indicatorObj,
        string name,
        bool isChargingIndicator,
        bool forceRecreate)
    {
        // ���һ򴴽��ڵ�
        if (indicatorObj == null)
        {
            Transform child = m_IndicatorRoot.transform.Find(name);
            if (child != null)
            {
                indicatorObj = child.gameObject;
            }
            else
            {
                indicatorObj = new GameObject(name);
                indicatorObj.AddComponent<RectTransform>();
                indicatorObj.transform.SetParent(m_IndicatorRoot.transform, false);
                indicatorObj.transform.localPosition = Vector3.zero;
                indicatorObj.transform.localRotation = Quaternion.identity;
            }

            // ��ȫ������Ӷ��󣨱���������Դ��
            SafeClearChildren(indicatorObj);
        }

        // ���ָʾ�����ͱ仯��ǿ���ؽ���������ָʾ��
        if (forceRecreate && indicator != null)
        {
            indicator.CleanUp();
            indicator = null;
        }

        // ���������ָʾ��ʵ��
        if (indicator == null)
        {
            indicator = IndicatorFactory.CreateIndicator(IndicatorType);
            if (indicator != null)
            {
                indicator.Initialize(indicatorObj, IndicatorMaterial);

                // ���ó�ʼ״̬
                if (isChargingIndicator)
                {
                    indicator.Hide();
                }
                else
                {
                    indicator.SetFillAmount(1f);
                    indicator.SetFillColor(new Color(1, 1, 1, 0.5f));
                }
            }
        }

        // ����ָʾ������
        if (indicator != null)
        {
            SyncParamsToIndicator(indicator);
        }
    }

    /// <summary>
    /// ��ȫ����ڵ��������Ӷ��󣨱���������Դ��
    /// </summary>
    private void SafeClearChildren(GameObject parent)
    {
        if (parent == null) return;

#if UNITY_EDITOR
        // ����� Prefab ��Դ�� Prefab ʵ����ֱ�ӷ��أ�������
        if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(parent) ||
            UnityEditor.PrefabUtility.IsPartOfPrefabInstance(parent))
        {
            return;
        }
#endif

        // ������ʱ�б��洢Ҫ���ٵ��Ӷ���
        var childrenToDestroy = new System.Collections.Generic.List<GameObject>();

        // �ռ������Ӷ���
        foreach (Transform child in parent.transform)
        {
            // ֻ���ӳ������󣨷���Դ��
            if (!IsAsset(child.gameObject))
            {
                childrenToDestroy.Add(child.gameObject);
            }
        }

        // �����Ӷ���
        if (childrenToDestroy.IsNullOrEmpty())
        {
            return;
        }
        foreach (var child in childrenToDestroy)
        {
            if (Application.isPlaying)
            {
                Destroy(child);
            }
            else
            {
                DestroyImmediate(child);
            }
        }
    }

    /// <summary>
    /// �������Ƿ�����Դ�����ǳ���ʵ����
    /// </summary>
    private bool IsAsset(GameObject obj)
    {
        // �ڱ༭�������Ƿ��� false
        if (!Application.isEditor) return false;

#if UNITY_EDITOR
        // �ڱ༭��ģʽ�¼������Ƿ�����Դ
        try
        {
            return UnityEditor.EditorUtility.IsPersistent(obj);
        }
        catch
        {
            // �����쳣ʱĬ�Ϸ��� false
            return false;
        }
#else
        return false;
#endif
    }

    /// <summary>
    /// ��������ָʾ����Դ
    /// </summary>
    private void CleanUpIndicators()
    {
        CleanUpIndicator(ref m_BaseIndicator, ref m_BaseIndicatorObj);
        CleanUpIndicator(ref m_ChargingIndicator, ref m_ChargingIndicatorObj);
        m_LastIndicatorType = IndicatorType; // �������ͼ�¼
    }

    /// <summary>
    /// ��������ָʾ����Դ
    /// </summary>
    private void CleanUpIndicator(ref IAttackIndicator indicator, ref GameObject indicatorObj)
    {
        if (indicator != null)
        {
            indicator.CleanUp();
            indicator = null;
        }

        if (indicatorObj != null)
        {
#if UNITY_EDITOR
            if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(indicatorObj) ||
                UnityEditor.PrefabUtility.IsPartOfPrefabInstance(indicatorObj))
            {
                indicatorObj = null;
                return;
            }
#endif
            // ֻ���ٳ������󣬲�������Դ
            if (!IsAsset(indicatorObj))
            {
                if (Application.isPlaying)
                {
                    Destroy(indicatorObj);
                }
                else
                {
                    DestroyImmediate(indicatorObj);
                }
            }
            indicatorObj = null;
        }
    }

    /// <summary>
    /// ͬ��������ָ��ָʾ��
    /// </summary>
    private void SyncParamsToIndicator(IAttackIndicator indicator)
    {
        if (indicator == null) return;

        switch (IndicatorType)
        {
            case IndicatorType.Sector:
                var s = indicator as SectorIndicator;
                if (s != null)
                {
                    s.Angle = SectorAngle;
                    s.Radius = SectorRadius;
                    s.Quality = SectorQuality;
                    s.UpdateParams();
                }
                break;

            case IndicatorType.OBB:
                var o = indicator as OBBIndicator;
                if (o != null)
                {
                    o.HalfExtents = ObbHalfExtents;
                    o.RotationEuler = ObbRotationEuler;
                    o.SetFillDirection(ObbFillDirection);
                    o.UpdateParams();
                }
                break;
            case IndicatorType.Circle:
                var c = indicator as CircleIndicator;
                if (c != null)
                {
                    c.Radius = CircleRadius;
                    c.Quality = CircleQuality;
                    c.UpdateParams();
                }
                break;
            case IndicatorType.Rectangle:
                var rect = indicator as RectangleIndicator;
                if (rect != null)
                {
                    rect.Width = RectangleWidth;
                    rect.Length = RectangleLength;
                    rect.UpdateParams();
                }
                break;

            case IndicatorType.Capsule:
                var cap = indicator as CapsuleIndicator;
                if (cap != null)
                {
                    cap.Radius = CapsuleRadius;
                    cap.Height = CapsuleHeight;
                    cap.UpdateParams();
                }
                break;

            case IndicatorType.CapsuleCast:
                var cc = indicator as CapsuleCastIndicator;
                if (cc != null)
                {
                    cc.Radius = CapsuleCastRadius;
                    cc.Height = CapsuleCastHeight;
                    cc.Range = CapsuleCastRange;
                    cc.UpdateParams();
                }
                break;

            case IndicatorType.Cone:
                var cone = indicator as ConeIndicator;
                if (cone != null)
                {
                    cone.Angle = ConeAngle;
                    cone.Height = ConeHeight;
                    cone.Quality = ConeQuality;
                    cone.UpdateParams();
                }
                break;

            case IndicatorType.Donut:
                var donut = indicator as DonutIndicator;
                if (donut != null)
                {
                    donut.InnerRadius = DonutInnerRadius;
                    donut.OuterRadius = DonutOuterRadius;
                    donut.Quality = DonutQuality;
                    donut.UpdateParams();
                }
                break;

            case IndicatorType.Cross:
                var cross = indicator as CrossIndicator;
                if (cross != null)
                {
                    cross.HalfWidth = CrossHalfWidth;
                    cross.MaxLength = CrossMaxLength;
                    cross.UpdateParams();
                }
                break;

            case IndicatorType.SphereCast:
                var sc = indicator as SphereCastIndicator;
                if (sc != null)
                {
                    sc.Radius = SphereCastRadius;
                    sc.Range = SphereCastRange;
                    sc.UpdateParams();
                }
                break;

            case IndicatorType.Parabola:
                var para = indicator as ParabolaIndicator;
                if (para != null)
                {
                    para.ProjectileSpeed = ParabolaProjectileSpeed;
                    para.ImpactRadius = ParabolaImpactRadius;
                    para.Gravity = ParabolaGravity;
                    para.UpdateParams();
                }
                break;
        }
    }

    /* ========== �����߼� ========== */
    private bool m_isCharging = false;
    private float m_chargeStart = 0f;

    private void Update()
    {
        if (!EnableCharging || !m_isCharging) return;

        float progress = GetChargeProgress();

        // ��������ָʾ��
        if (m_ChargingIndicator != null)
        {
            m_ChargingIndicator.SetFillAmount(progress);
            Color c = Color.Lerp(ChargeFillColor, ChargeCompleteColor, progress);
            m_ChargingIndicator.SetFillColor(c);
        }
    }

    /// <summary>
    /// ��ʼ����
    /// </summary>
    public void StartCharging()
    {
        if (m_isCharging) return;

        m_isCharging = true;
        m_chargeStart = Time.time;

        // ȷ��ָʾ������
        if (m_ChargingIndicator == null)
        {
            CreateOrUpdateIndicator(
                ref m_ChargingIndicator,
                ref m_ChargingIndicatorObj,
                "ChargingIndicator",
                true,
                false);
        }

        // ��ʾ����ָʾ�������ػ���ָʾ��
        if (m_ChargingIndicator != null)
        {
            m_ChargingIndicator.Show();
        }
        if (m_BaseIndicator != null)
        {
            m_BaseIndicator.Hide();
        }
    }

    /// <summary>
    /// ��������
    /// </summary>
    public void EndCharging()
    {
        if (!m_isCharging) return;

        m_isCharging = false;

        // ��������ָʾ������ʾ����ָʾ��
        if (m_ChargingIndicator != null)
        {
            m_ChargingIndicator.Hide();
        }
        if (m_BaseIndicator != null)
        {
            m_BaseIndicator.Show();
        }
    }

    public bool IsCharging() => m_isCharging;

    /// <summary>
    /// ��ȡ��������
    /// </summary>
    public float GetChargeProgress()
    {
        if (!m_isCharging) return 0f;
        float elapsed = Time.time - m_chargeStart;
        return Mathf.Clamp01(elapsed / MaxChargeTime);
    }

    /// <summary>
    /// ��ȡ�����ȼ�
    /// </summary>
    public int GetChargeLevel()
    {
        float p = GetChargeProgress();
        if (p <= 0f) return 0;

        if (p < 0.34f) return 1;
        if (p < 0.67f) return 2;
        return 3;
    }
}
